package com.foreveross.bsl.common.utils.exception.handle;

import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.foreveross.bsl.common.utils.bean.ExceptionUtils;
import com.foreveross.bsl.common.utils.exception.ApplicationException;
import com.foreveross.bsl.common.utils.exception.ExceptionSpec;
import com.foreveross.bsl.common.utils.exception.RemoteInvokeException;
import com.foreveross.bsl.common.utils.mapper.JsonMapper;



/**
 * 应用异常处理类，可以在此类中分别处理不同的处理，针对不同的异常做展现。
 *
 * @author Wangyi
 * @version v1.0
 *
 * @date 2013-7-5
 * 
 * @author ning 2013-8-20
 *
 */
public class ApplicationExceptionsHandler extends SimpleMappingExceptionResolver {
	
	private static final Logger log = LoggerFactory.getLogger(ApplicationExceptionsHandler.class);
	
	private JsonMapper jsonMapper = JsonMapper.nonEmptyMapper();
	
	@Override
	protected ModelAndView doResolveException(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex) {
		
		if (!isAjaxRequest(request)) {
			return this.handleForNormalRequest(request, response, ex);
		} else {
			this.handleForAjaxRequest(response, ex);
			return null;
		}
	}

	private boolean isAjaxRequest(HttpServletRequest request) {
		return (request.getHeader("accept").indexOf("application/json") != -1 || (request
				.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With")
				.indexOf("XMLHttpRequest") != -1));
	}
	
	private void handleForAjaxRequest(HttpServletResponse response, Exception ex){
		log.error(ex.getMessage(), ex);
		ExceptionSpec spec=null;
		if(ex instanceof ApplicationException){
			ApplicationException a = (ApplicationException)ex;
			String msg = ExceptionUtils.formatException(a);
			spec=new ExceptionSpec(a.getCode(), msg, new Date());
		} else if(ex instanceof RemoteInvokeException){
			RemoteInvokeException re = (RemoteInvokeException)ex;
			spec=re.getExceptionSpec();
		} else {
			spec=new ExceptionSpec(ex.getMessage(), new Date());
		}
		Writer writer = null;
		try {
			response.setContentType("text/x-json;charset=UTF-8");
			writer = response.getWriter();
			String json=this.jsonMapper.toJson(spec);
			writer.write(json);
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		} finally{
			try {
				writer.close();
			} catch (IOException e) {
			}
		}
	}
	
	private ModelAndView handleForNormalRequest(HttpServletRequest request, HttpServletResponse response, Exception ex){
		Map<String, Object> model = new HashMap<String, Object>();  
		String viewName = determineViewName(ex, request);
		String errMsg = "";
		if (viewName != null) {
			if(viewName.indexOf(".") != -1){
				viewName = viewName.substring(0, viewName.lastIndexOf("."));
			}
		}
		Integer statusCode = determineStatusCode(request, viewName);
		if (statusCode != null) {
			applyStatusCodeIfPossible(request, response, statusCode);
		}
		if(ex instanceof ApplicationException){
			ApplicationException a = (ApplicationException)ex;
			log.error(a.getCode() + ":" + a.getMessage(), a);
			errMsg = ExceptionUtils.formatException(a);
		} else if(ex instanceof RemoteInvokeException){
			log.error(ex.getMessage(), ex);
			RemoteInvokeException re = (RemoteInvokeException)ex;
			errMsg=re.getExceptionSpec().toString();
		} else {
			log.error(ex.getMessage(), ex);
			errMsg = ExceptionUtils.formatException(ex);
		}
		model.put("errorMsg", errMsg);
		return new ModelAndView(viewName, model);
	}
	
}
